#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <unistd.h>
#include <iostream>
#include <cstdlib>
#include <pthread.h>
const std::string IP = "0.0.0.0";
class TcpSocket
{
public:
    TcpSocket(uint16_t port, const std::string ip = IP)
        :_listen_sockfd(-1)
       ,_ip(ip)
       ,_port(port)
    {}

    bool Init()
    {
        _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listen_sockfd < 0)
        {
            perror("ListenSocket create fail");
            return false;
        }
        _addr.sin_family = AF_INET;
        _addr.sin_port = htons(_port);
        int err = inet_aton(_ip.c_str(), &_addr.sin_addr);
        if(err == 0)
        {
            std::cerr << "ip is invalid" << std::endl;
            return false;
        }
        return true;
    }



    bool Bind()
    {
        int err = bind(_listen_sockfd, (sockaddr*)&_addr, sizeof(_addr));
        if(err != 0)
        {
            perror("Bind fail");
            return false;
        }
        return true;

    }


    bool Listen()
    {
        int err = listen(_listen_sockfd, 5);
        if(err!= 0)
        {
            perror("Listen fail");
            return false;
        }
        return true;
    }


    int Accept(sockaddr_in& client_addr, socklen_t& len)
    {
        int sockfd = accept(_listen_sockfd, (sockaddr*)&client_addr, &len);
        if(sockfd < 0)
        {
            perror("Accept fail");
            return -1;
        }
        return sockfd;

    }


    bool Connect(int sockfd)
    {
        
        int err = connect(sockfd, (sockaddr*)&_addr, sizeof(_addr));
        if(err!= 0)
        {
            perror("Connect fail");
            return false;
        }
        return true;
    }
    ~TcpSocket()
    {
        int err = close(_listen_sockfd);
        if(err < 0)
        {
            perror("Close socket fail");
        }
    }


    std::string GetIp()const
    {
        return _ip;
    }

    uint16_t GetPort()const
    {
        return _port;
    }


    int Send(int sockfd, const std::string& message)
    {
        int WriteSize = write(sockfd, message.c_str(), message.size());
        if(WriteSize < 0)
        {
            perror("Send fail");
        }
        return WriteSize;
    }


    int Recv(int sockfd, std::string& message)
    {
        char buf[1024];
        ssize_t read_size = read(sockfd, buf, sizeof(buf) - 1);
        if(read_size < 0)
        {
            perror("Recv fail");
        }
        else if(read_size == 0)
        {
            std::cout << "peer shutdown" << std::endl;
        }
        buf[read_size] = '\0';
        message.assign(buf);
        return read_size;

    }
private:
    int _listen_sockfd;
    sockaddr_in _addr;
    std::string _ip;
    uint16_t _port;

};
